package net.atomarrow.action;

import net.atomarrow.bean.UploadFile;
import net.atomarrow.configs.Config;
import net.atomarrow.controllers.ParamParser;
import net.atomarrow.controllers.converter.TypeMismatchException;
import net.atomarrow.ioc.ApplicationContext;
import net.atomarrow.util.ClassUtil;

import java.io.File;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Time;
import java.util.Date;

/**
 * @author Boolone
 * @date 2020/1/15
 */
public class ParamInfo {

    private Parameter parameter;

    private ParamFeature feature;


    public ParamInfo(Parameter parameter) {
        this.parameter = parameter;

        this.feature = analyzeParamFeature(parameter.getParameterizedType());

        UrlParamIndex index = parameter.getAnnotation(UrlParamIndex.class);

        if (index != null) {
            this.feature.setUrlParamIndex(index.value());
        }

    }

    /**
     * 从Request中提取对应的参数值
     * @param request
     * @return
     */
    public Object extractValueFromRequest(AtomarrowRequest request) {

        ParamParser parser = ApplicationContext.get(ParamParser.class);
        Object value = null;
        Integer urlParamIndex = getUrlParamIndex();

        switch (this.getParamType()) {
            case STRING:

                if (urlParamIndex != null) {
                    value = parser.parseRequestString(urlParamIndex, request);
                } else {
                    value = parser.parseRequestString(parameter.getName(), request);
                }
                break;

            case INT:

                if (urlParamIndex != null) {
                    value = parser.parseRequestInteger(urlParamIndex, request);
                } else {
                    value = parser.parseRequestInteger(parameter.getName(), request);
                }

                break;

            case LONG:

                if (urlParamIndex != null) {
                    value = parser.parseRequestLong(urlParamIndex, request);
                } else {
                    value = parser.parseRequestLong(parameter.getName(), request);
                }
                break;

            case DOUBLE:

                if (urlParamIndex != null) {
                    value = parser.parseRequestDouble(urlParamIndex, request);
                } else {
                    value = parser.parseRequestDouble(parameter.getName(), request);
                }
                break;

            case BOOLEAN:

                if (urlParamIndex != null) {
                    value = parser.parseRequestBoolean(urlParamIndex, request);
                } else {
                    value = parser.parseRequestBoolean(parameter.getName(), request);
                }
                break;

            case DATE:

                if (urlParamIndex != null) {
                    value = parser.parseRequestDate(urlParamIndex, request);
                } else {
                    value = parser.parseRequestDate(parameter.getName(), request);
                }
                break;

            case TIME:

                value = parser.parseRequestTime(parameter.getName(), request);

                break;
            case ENUM:
                if (urlParamIndex != null) {
                    value = parser.parseRequestEnum(urlParamIndex, parameter.getType(), request);
                } else {
                    value = parser.parseRequestEnum(parameter.getName(), parameter.getType(), request);
                }
                break;

            case ARRAY:

                value = parser.parseRequestArray(parameter.getName(), parameter.getParameterizedType(), getComponentClass(), request);
                break;

            case LIST:

                if (getComponentClass() == UploadFile.class) { //上传的文件
                    value = parser.getFiles();
                } else {
                    value = parser.parseRequestList(parameter.getName(), parameter.getParameterizedType(), getComponentClass(),  request);
                }
                break;

            case FILE:

                value = parser.getFile(parameter.getName(), Config.getConfig().configUploadPath());

                break;

            case POJO:

                value = parser.parseRequestObject(parameter.getName(), parameter.getParameterizedType(), request);


                break;

        }

        if (value == null) { //基本数据类型要赋默认值，用null会报错
            value = ClassUtil.getDefaultValue(parameter.getType());
        }
        return value;
    }

    private String getUploadPath(String uploadPath) {
        if(uploadPath.startsWith("/")){
            if(uploadPath.length()==1){
                uploadPath="";
            }else{
                uploadPath=uploadPath.substring(1);
            }
        }
        return uploadPath;
    }

    /**
     * 解析并生成特征
     * @param type
     * @return
     */
    private ParamFeature analyzeParamFeature(Type type) {

        this.feature = new ParamFeature();

        Class clazz = null;

        if (type instanceof Class) {

            clazz = (Class) type;
            feature.setParamType(analyzeParamType(clazz));

        } else if (type instanceof ParameterizedType) {

            clazz = (Class)((ParameterizedType) type).getRawType();
            feature.setParamType(analyzeParamType(clazz));

        } else if(type instanceof GenericArrayType) {

            feature.setParamType(ParamType.ARRAY);

        } else {

            throw new TypeMismatchException("不支持进行参数转化的类型：" + type);

        }

        if (feature.getParamType() == ParamType.ARRAY) {

            feature.setComponentClass(analyzeArrayComponentFeatures(type));

        } else if (feature.getParamType() == ParamType.LIST) {

            feature.setComponentClass(analyzeListElementFeatures(type));

        }

        return feature;
    }





    /**
     * 解析List的元素特征
     * @param listType
     * @return
     */
    private Class analyzeListElementFeatures(Type listType) {

        if (listType instanceof ParameterizedType == false) {
            throw new TypeMismatchException("必须指定具体的泛型类型才可进行参数转化："  + listType);
        }
        Type type = ((ParameterizedType)listType).getActualTypeArguments()[0];

        if ((type instanceof Class) == false) {
            throw new TypeMismatchException("目前不支持List泛型中 还有泛型："  + listType);
        }

        return (Class)type;
    }

    /**
     * 解析数组的子元素特征
     * @param arrayType
     * @return
     */
    private Class analyzeArrayComponentFeatures(Type arrayType) {
        Class componentType = null;
        if (arrayType instanceof Class) {
            componentType = ((Class)arrayType).getComponentType();
        } else if(arrayType instanceof GenericArrayType) {
            throw new  TypeMismatchException("目前不支持数组中有泛型类型：" + arrayType);
        }
        return componentType;
    }

    /**
     * 解析是哪个
     * @param clazz
     * @return
     */
    private ParamType analyzeParamType(Class clazz) {

        if (clazz == String.class) {
            return ParamType.STRING;
        }

        if (clazz == Integer.class || clazz == int.class) {
            return ParamType.INT;
        }

        if (clazz == Double.class || clazz == double.class) {
            return ParamType.DOUBLE;
        }

        if (clazz == Long.class || clazz == long.class) {
            return ParamType.LONG;
        }

        if (clazz == Boolean.class || clazz == boolean.class) {
            return ParamType.BOOLEAN;
        }

        if (clazz == Float.class || clazz == float.class) {
            return ParamType.BOOLEAN;
        }

        if (clazz == Date.class) {
            return ParamType.DATE;
        }

        if (clazz == Time.class) {
            return ParamType.TIME;
        }

        if (clazz == UploadFile.class) {
            return ParamType.FILE;
        }

        if (clazz == File.class) {
            throw new TypeMismatchException("请使用" + UploadFile.class.getCanonicalName() + "代替 File 来读取文件");
        }

        if (clazz.isEnum()) {
            return ParamType.ENUM;
        }
        if (ClassUtil.isArrayType(clazz)) {
            return ParamType.ARRAY;
        }

        if (ClassUtil.isListType(clazz)) {
            return ParamType.LIST;
        }


        return ParamType.POJO;

    }
    /**
     * 原生参数对象
     * @return
     */
    public Parameter getParameter() {
        return parameter;
    }

    /**
     * 获取@UrlParamIndex注解指明的索引
     * @return
     */
    public Integer getUrlParamIndex() {
        return this.feature.getUrlParamIndex();
    }

    public ParamType getParamType() {
        return this.feature.getParamType();
    }

    public Class getComponentClass() {
        return this.feature.getComponentClass();
    }

    /**
     * 参数特征
     */
    private static class ParamFeature {

        private Integer urlParamIndex; //是否从/x-x-x 类型的url读取参数，是的话，设定url哪个位置的参数
        private ParamType paramType; //参数类型
        private Class componentClass; // 元素类型, 适用于数组和List类型参数

        public ParamType getParamType() {
            return paramType;
        }

        public void setParamType(ParamType paramType) {
            this.paramType = paramType;
        }

        public Integer getUrlParamIndex() {
            return urlParamIndex;
        }

        public void setUrlParamIndex(Integer urlParamIndex) {
            this.urlParamIndex = urlParamIndex;
        }

        public Class getComponentClass() {
            return componentClass;
        }

        public void setComponentClass(Class componentClass) {
            this.componentClass = componentClass;
        }
    }

}
